package com.qiuling.iot.server;

import com.alibaba.fastjson.JSONObject;
import com.qiuling.iot.Exception.code.FunctionCodeEnum;
import com.qiuling.iot.entity.SocketServer;
import com.qiuling.iot.vo.req.ServerSendReqVO;
import com.qiuling.iot.vo.resp.ServerReceiveRespVO;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.Date;

/**
 * @Author：zhangqiang
 * @Description：
 * @Date：Created in 20:40 2020/2/23
 * @Modified By：
 */
@Slf4j
@Data
public class ConnectionThread extends Thread {
    /**
     * 客户端的socket
     */
    private Socket socket;

    /**
     * 服务socket
     */
    private SocketServer socketServer;

    /**
     * 封装的客户端连接socket
     */
    private Connection connection;

    /**
     * 判断当前连接是否运行
     */
    private boolean isRunning;

    public ConnectionThread(Socket socket, SocketServer socketServer) {
        this.socket = socket;
        this.socketServer = socketServer;
        connection = new Connection(socket, this);
        Date now = new Date();
        connection.setCreateTime(now);
        connection.setLastOnTime(now);
        isRunning = true;
    }

    @Override
    public void run() {
        while (isRunning) {
            // Check whether the socket is closed.
            if (socket.isClosed()) {
                isRunning = false;
                break;
            }
            BufferedReader reader;
            try {
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String message;
                while ((message = reader.readLine()) != null) {
                    log.info("服务端收到消息：" + message);
                    ServerReceiveRespVO receiveVO;
                    try {
                        receiveVO = JSONObject.parseObject(message, ServerReceiveRespVO.class);
                    } catch (Exception e) {
                        ServerSendReqVO vo = new ServerSendReqVO();
                        vo.setFunctionCode(999);
                        vo.setErrorMessage("data error");
                        connection.println(JSONObject.toJSONString(vo));
                        break;
                    }
                    Integer functionCode = receiveVO.getFunctionCode();
                    /**
                     * 处理心跳
                     */
                    if (functionCode.equals(FunctionCodeEnum.HEART.getValue())) {
                        //心跳类型
                        connection.setLastOnTime(new Date());
                        ServerSendReqVO vo = new ServerSendReqVO();
                        vo.setFunctionCode(FunctionCodeEnum.HEART.getValue());
                        connection.println(JSONObject.toJSONString(vo));
                    }
                    /**
                     * 处理登录
                     */
                    else if (functionCode.equals(FunctionCodeEnum.LOGIN.getValue())) {
                        //登陆，身份验证
                        String equipmentCode = receiveVO.getEquipmentCode();
                        if (socketServer.getLoginHandler().canLogin(equipmentCode)) {
                            connection.setLogin(true);
                            connection.setEquipmentCode(equipmentCode);
                            if (socketServer.getExistSocketMap().containsKey(equipmentCode)) {
                                //存在已登录的用户，发送登出指令并主动关闭该socket
                                Connection existConnection = socketServer.getExistSocketMap().get(equipmentCode);
                                ServerSendReqVO vo = new ServerSendReqVO();
                                vo.setStatusCode(999);
                                vo.setFunctionCode(FunctionCodeEnum.MESSAGE.getValue());
                                vo.setErrorMessage("force logout");
                                existConnection.println(JSONObject.toJSONString(vo));
                                existConnection.getConnectionThread().stopRunning();
                                log.error("用户被客户端重入踢出，equipmentCode:{}", equipmentCode);
                            }
                            //添加到已登录map中
                            socketServer.getExistSocketMap().put(equipmentCode, connection);
                        } else {
                            //用户鉴权失败
                            ServerSendReqVO vo = new ServerSendReqVO();
                            vo.setStatusCode(999);
                            vo.setFunctionCode(FunctionCodeEnum.MESSAGE.getValue());
                            vo.setErrorMessage("user valid failed");
                            connection.println(JSONObject.toJSONString(vo));
                            log.error("用户鉴权失败,equipmentCode:{}", equipmentCode);
                        }
                    }
                    /**
                     * 处理其他信息
                     */
                    else if (functionCode.equals(FunctionCodeEnum.MESSAGE.getValue())) {
                        //发送一些其他消息等
                        socketServer.getMessageHandler().onReceive(connection, receiveVO);
                    }
                    /**
                     * 退出登录
                     */
                    else if (functionCode.equals(FunctionCodeEnum.CLOSE.getValue())) {
                        //主动关闭客户端socket
                        log.info("客户端主动登出socket");
                        this.stopRunning();
                    }

                }
            } catch (IOException e) {
                log.error("ConnectionThread.run failed. IOException:{}", e.getMessage());
                this.stopRunning();
            }
        }
    }

    public void stopRunning() {
        if (this.connection.isLogin()) {
            log.info("停止一个socket连接,ip:{},equipmentCode:{}", this.socket.getInetAddress().toString(),
                    this.connection.getEquipmentCode());
        } else {
            log.info("停止一个还未身份验证的socket连接,ip:{}", this.socket.getInetAddress().toString());
        }
        isRunning = false;
        try {
            socket.close();
        } catch (IOException e) {
            log.error("ConnectionThread.stopRunning failed.exception:{}", e);
        }
    }
}
